package com.yupi.springbootinit.statemachine.aspect;

import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.statemachine.annotation.StateTransitionPermission;
import com.yupi.springbootinit.statemachine.annotation.RequireDepartment;
import com.yupi.springbootinit.statemachine.core.StateContext;
import com.yupi.springbootinit.statemachine.permission.PermissionManager;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 状态转换权限验证切面
 * 拦截带有权限验证注解的方法，进行权限检查
 */
@Slf4j
@Aspect
@Component
public class StateTransitionPermissionAspect {
    
    @Autowired
    private PermissionManager permissionManager;
    
    private final ExpressionParser parser = new SpelExpressionParser();
    
    /**
     * 拦截带有StateTransitionPermission注解的方法
     */
    @Around("@annotation(com.yupi.springbootinit.statemachine.annotation.StateTransitionPermission)")
    public Object checkStateTransitionPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        StateTransitionPermission annotation = method.getAnnotation(StateTransitionPermission.class);
        
        // 如果权限验证被禁用，直接执行方法
        if (!annotation.enabled()) {
            return joinPoint.proceed();
        }
        
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        StateContext context = findStateContext(args);
        
        if (context == null) {
            log.warn("方法[{}]未找到StateContext参数，跳过权限验证", method.getName());
            return joinPoint.proceed();
        }
        
        // 执行权限验证
        boolean hasPermission = validatePermission(context, annotation, method, args);
        
        if (!hasPermission) {
            String errorMessage = StringUtils.hasText(annotation.message()) ? 
                annotation.message() : "权限不足，无法执行状态转换操作";
            
            // 记录权限验证失败日志
            if (annotation.logPermissionCheck()) {
                permissionManager.logPermissionCheck(
                    context.getOperatorId(), 
                    "STATE_TRANSITION:" + context.getEntityType(), 
                    false
                );
            }
            
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, errorMessage);
        }
        
        // 记录权限验证成功日志
        if (annotation.logPermissionCheck()) {
            permissionManager.logPermissionCheck(
                context.getOperatorId(), 
                "STATE_TRANSITION:" + context.getEntityType(), 
                true
            );
        }
        
        // 执行原方法
        return joinPoint.proceed();
    }
    
    /**
     * 拦截带有RequireDepartment注解的方法
     */
    @Around("@annotation(com.yupi.springbootinit.statemachine.annotation.RequireDepartment)")
    public Object checkDepartmentPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequireDepartment annotation = method.getAnnotation(RequireDepartment.class);
        
        // 获取用户ID（从方法参数中查找）
        Long userId = findUserId(joinPoint.getArgs());
        if (userId == null) {
            log.warn("方法[{}]未找到用户ID参数，跳过部门权限验证", method.getName());
            return joinPoint.proceed();
        }
        
        // 执行部门权限验证
        boolean hasPermission = validateDepartmentPermission(userId, annotation);
        
        if (!hasPermission) {
            String errorMessage = StringUtils.hasText(annotation.message()) ? 
                annotation.message() : "部门权限不足，无法访问此功能";
            
            // 记录权限验证失败日志
            if (annotation.logAccess()) {
                Long userDeptId = permissionManager.getUserDepartmentId(userId);
                log.warn("用户[{}]部门[{}]访问方法[{}]权限不足，需要部门权限: {}", 
                    userId, userDeptId, method.getName(), Arrays.toString(annotation.departmentIds()));
            }
            
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, errorMessage);
        }
        
        // 记录权限验证成功日志
        if (annotation.logAccess()) {
            Long userDeptId = permissionManager.getUserDepartmentId(userId);
            log.debug("用户[{}]部门[{}]成功访问方法[{}]", userId, userDeptId, method.getName());
        }
        
        // 执行原方法
        return joinPoint.proceed();
    }
    
    /**
     * 验证状态转换权限
     */
    private boolean validatePermission(StateContext context, StateTransitionPermission annotation, 
                                     Method method, Object[] args) {
        
        // 如果有自定义条件表达式，优先使用
        if (StringUtils.hasText(annotation.condition())) {
            return evaluateCondition(annotation.condition(), method, args, context);
        }
        
        // 使用默认的状态转换权限验证
        return permissionManager.validateStateTransition(context);
    }
    
    /**
     * 验证部门权限
     */
    private boolean validateDepartmentPermission(Long userId, RequireDepartment annotation) {
        Long userDeptId = permissionManager.getUserDepartmentId(userId);
        if (userDeptId == null) {
            return false;
        }
        
        // 管理员权限检查
        if (annotation.allowAdmin() && PermissionManager.ADMIN_DEPT_ID.equals(userDeptId)) {
            return true;
        }
        
        // 检查用户部门是否在允许的部门列表中
        long[] allowedDeptIds = annotation.departmentIds();
        if (allowedDeptIds.length == 0) {
            // 如果没有指定部门限制，则允许所有部门访问
            return true;
        }
        
        for (long deptId : allowedDeptIds) {
            if (userDeptId.equals(deptId)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 从方法参数中查找StateContext
     */
    private StateContext findStateContext(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof StateContext) {
                return (StateContext) arg;
            }
        }
        return null;
    }
    
    /**
     * 从方法参数中查找用户ID
     */
    private Long findUserId(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Long) {
                return (Long) arg;
            }
            // 如果参数是StateContext，从中获取操作用户ID
            if (arg instanceof StateContext) {
                return ((StateContext) arg).getOperatorId();
            }
        }
        return null;
    }
    
    /**
     * 评估SpEL条件表达式
     */
    private boolean evaluateCondition(String condition, Method method, Object[] args, StateContext context) {
        try {
            Expression expression = parser.parseExpression(condition);
            EvaluationContext evaluationContext = new StandardEvaluationContext();
            
            // 设置方法参数到上下文
            String[] paramNames = getParameterNames(method);
            for (int i = 0; i < args.length && i < paramNames.length; i++) {
                evaluationContext.setVariable(paramNames[i], args[i]);
            }
            
            // 设置StateContext到上下文
            evaluationContext.setVariable("context", context);
            evaluationContext.setVariable("permissionManager", permissionManager);
            
            Object result = expression.getValue(evaluationContext);
            return Boolean.TRUE.equals(result);
        } catch (Exception e) {
            log.error("评估权限条件表达式失败: {}", condition, e);
            return false;
        }
    }
    
    /**
     * 获取方法参数名称（简化实现）
     */
    private String[] getParameterNames(Method method) {
        // 简化实现，实际项目中可以使用Spring的ParameterNameDiscoverer
        int paramCount = method.getParameterCount();
        String[] names = new String[paramCount];
        for (int i = 0; i < paramCount; i++) {
            names[i] = "arg" + i;
        }
        return names;
    }
}